home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
jnos
/
jnos_src
/
dialer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
16KB
|
616 lines
/* Automatic SLIP/PPP line dialer.
*
* Copyright 1991 Phil Karn, KA9Q
*
* Mar '91 Bill Simpson & Glenn McGregor
* completely re-written;
* human readable control file;
* includes wait for string, and speed sense;
* dials immediately when invoked.
* May '91 Bill Simpson
* re-ordered command line;
* allow dial only;
* allow inactivity timeout without ping.
* Sep '91 Bill Simpson
* Check known DTR & RSLD state for redial decision
*
* Mods by PA0GRI (newsession parameters)
*
* Mods by KF8NH: iffailed, begin/end
*/
#include <ctype.h>
#include "global.h"
#ifdef DIALER
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "netuser.h"
#ifdef LINUX
#include "lxasy.h"
#else
#include "i8250.h"
#endif
#include "asy.h"
#include "tty.h"
#include "session.h"
#include "socket.h"
#include "cmdparse.h"
#include "devparam.h"
#include "icmp.h"
#include "files.h"
#include "main.h"
#include "trace.h"
#define MIN_INTERVAL 5L
#define MAXDEPTH 8
static int Failmode = 0;
static char Failed;
static char Depth;
static char Skip[MAXDEPTH];
static char SkipOverride;
static char OverrideDepth;
static int redial __ARGS((struct iface *ifp,char *file));
static int dodial_nothing __ARGS((int argc,char *argv[],void *p));
static int dodial_begin __ARGS((int argc,char *argv[],void *p));
static int dodial_control __ARGS((int argc,char *argv[],void *p));
static int dodial_end __ARGS((int argc,char *argv[],void *p));
static int dodial_exit __ARGS((int argc,char *argv[],void *p));
static int dodial_failmode __ARGS((int argc,char *argv[],void *p));
static int dodial_iffail __ARGS((int argc,char *argv[],void *p));
static int dodial_ifok __ARGS((int argc,char *argv[],void *p));
static int dodial_send __ARGS((int argc,char *argv[],void *p));
static int dodial_speed __ARGS((int argc,char *argv[],void *p));
static int dodial_status __ARGS((int argc,char *argv[],void *p));
static int dodial_wait __ARGS((int argc,char *argv[],void *p));
static struct cmds dial_cmds[] = {
"", dodial_nothing, 0, 0, "",
"begin", dodial_begin, 0, 1, "begin",
"control", dodial_control, 0, 2, "control up | down",
"end", dodial_end, 0, 1, "end",
"exit", dodial_exit, 0, 1, "exit",
"failmode", dodial_failmode,0, 2, "failmode on | off",
"iffail", dodial_iffail, 0, 2, "iffail \"command\"",
"ifok", dodial_ifok, 0, 2, "ifok \"command\"",
"send", dodial_send, 0, 2,
"send \"string\" [<milliseconds>]",
"speed", dodial_speed, 0, 2, "speed <bps>",
"status", dodial_status, 0, 2, "status up | down",
"wait", dodial_wait, 0, 2,
"wait <milliseconds> [ \"string\" [speed] ]",
NULLCHAR, NULLFP, 0, 0, "Unknown command",
};
/* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
* <iface> must be asy type
* <filename> contains commands which are executed.
* missing: kill outstanding dialer.
* <seconds> interval to check for activity on <iface>.
* <pings> number of missed pings before redial.
* <hostid> interface to ping.
*/
int
dodialer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp;
struct asy *ap;
int32 interval = 0L; /* in seconds */
int32 last_wait = 0L;
int32 target = 0L;
int pings = 0;
int countdown;
char *filename;
char *ifn;
int result;
int s;
if((ifp = if_lookup(argv[1])) == NULLIF){
tprintf(Badinterface,argv[1]);
return 1;
}
if( ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp ){
tprintf("Interface %s not asy port\n",argv[1]);
return 1;
}
if(ifp->supv != NULLPROC){
while ( ifp->supv != NULLPROC ) {
alert(ifp->supv, EABORT);
pwait(NULL);
}
tprintf("dialer terminated on %s\n",argv[1]);
}
if ( argc < 3 ) {
/* just terminating */
return 0;
}
chname( Curproc, ifn = if_name( ifp, " dialer" ) );
free( ifn );
filename = rootdircat(argv[2]);
/* handle minimal command (just thru filename) */
if ( argc < 4 ) {
/* just dialing */
result = redial(ifp, filename);
if ( filename != argv[2] )
free(filename);
return result;
/* get polling interval (arg 3) */
} else if ( (interval = atol(argv[3])) <= MIN_INTERVAL ) {
tprintf("interval must be > %ld seconds\n", MIN_INTERVAL);
return 1;
}
/* get the number of pings before redialing (arg 4) */
if ( argc < 5 ) {
} else if ( (pings = atoi(argv[4])) <= 0 ){
tprintf("pings must be > 0\n");
return 1;
}
/* retrieve the host name (arg 5) */
if ( argc < 6 ) {
} else if ( (target = resolve(argv[5])) == 0L ) {
tprintf(Badhost,argv[5]);
return 1;
}
countdown = pings;
ifp->supv = Curproc;
ap = &Asy[ ifp->dev ];
while ( !main_exit ) {
int32 wait_for = interval;
/*
* N.B. Eventually, when the rest of this is stable, I will
* look into supporting DTR and RTS. For now, it's enough to
* just have the Linux version of the code work.
*/
#ifndef LINUX
if ( ap->dtr_usage == FOUND_DOWN
|| ap->dtr_usage == MOVED_DOWN
|| ap->rlsd_line_control == MOVED_DOWN ) {
/* definitely down */
if ( redial(ifp,filename) < 0 )
break;
} else
#endif
if ( ifp->lastrecv >= last_wait ) {
/* got something recently */
wait_for -= secclock() - ifp->lastrecv;
countdown = pings;
} else if ( countdown < 1 ) {
/* we're down, or host we ping is down */
if ( redial(ifp,filename) < 0 )
break;
countdown = pings;
} else if ( target != 0L
&& (s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) != -1 ) {
pingem(s,target,0,(int16)s,0);
close_s(s);
countdown--;
} else if ( ifp->echo != NULLFP ) {
(*ifp->echo)(ifp,NULLBUF);
countdown--;
}
last_wait = secclock();
if ( wait_for != 0L ) {
alarm( wait_for * 1000L );
if ( pwait( &(ifp->supv) ) == EABORT )
break;
alarm(0L); /* clear alarm */
}
}
if ( filename != argv[2] )
free(filename);
ifp->supv = NULLPROC; /* We're being terminated */
return 0;
}
/* execute dialer commands
* returns: -1 fatal error, 0 OK, 1 try again
*/
static int
redial( ifp, file )
struct iface *ifp;
char *file;
{
char *inbuf, *intmp;
FILE *fp;
int (*rawsave) __ARGS((struct iface *,struct mbuf *));
struct session *sp;
int result = 0;
int save_input = Curproc->input;
int save_output = Curproc->output;
if((fp = fopen(file,READ_TEXT)) == NULLFILE){
tprintf("redial: can't read %s\n",file);
return -1; /* Causes dialer proc to terminate */
}
/* Save output handler and temporarily redirect output to null */
if(ifp->raw == bitbucket){
tprintf("redial: tip or dialer already active on %s\n",ifp->name);
return -1;
}
/* allocate a session descriptor */
if ( (sp = newsession( ifp->name, DIAL, 0 )) == NULLSESSION ) {
tputs(TooManySessions);
return 1;
}
tprintf( "Dialing on %s\n\n", ifp->name );
/* Save output handler and temporarily redirect output to null */
rawsave = ifp->raw;
ifp->raw = bitbucket;
/* Suspend the packet input driver. Note that the transmit driver
* is left running since we use it to send buffers to the line.
*/
suspend(ifp->rxproc);
#ifdef notdef
tprintf("rlsd: 0x%02x, dtr: 0x%02x\n",
Asy[ifp->dev].rlsd_line_control,
Asy[ifp->dev].dtr_usage );
#endif
Failed = 0;
Depth = 0;
Skip[0] = 0;
SkipOverride = -1;
inbuf = mallocw(BUFSIZ);
intmp = mallocw(BUFSIZ);
while ( fgets( inbuf, BUFSIZ, fp ) != NULLCHAR ) {
strcpy(intmp,inbuf);
rip( intmp );
log( -1, "%s dialer: %s", ifp->name, intmp );
if( (result = cmdparse(dial_cmds,inbuf,ifp)) != 0 ){
if (Failmode)
Failed = 1;
else
{
tprintf("input line: %s",intmp);
break;
}
}
else
Failed = 0;
if (Depth == -1)
break;
if (SkipOverride != -1)
{
Skip[OverrideDepth] = SkipOverride;
SkipOverride = -1;
}
}
if (Depth > 0)
tprintf("Warning: %d unmatched `begin's in command file\n", Depth);
free(inbuf);
free(intmp);
fclose(fp);
if ( result == 0 ) {
ifp->lastsent = ifp->lastrecv = secclock();
}
ifp->raw = rawsave;
resume(ifp->rxproc);
tprintf( "\nDial %s complete\n", ifp->name );
/* Wait for awhile, so the user can read the screen,
* AND to give it time to send some packets on the new connection!
*/
/* ten seconds is an AWFULLY long time...
pause( 10000L );
*/
pause(2000L);
freesession( sp );
Curproc->input = save_input;
Curproc->output = save_output;
return result;
}
static int
dodial_control(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
int param;
if (Skip[Depth])
return 0;
tprintf("control %s %ld\n", argv[1], atol(argv[2]));
if ( ifp->ioctl == NULL )
return -1;
if ( (param = devparam( argv[1] )) == -1 )
return -1;
(*ifp->ioctl)( ifp, param, TRUE, atol( argv[2] ) );
return 0;
}
static int
dodial_send(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
struct mbuf *bp;
if (Skip[Depth])
return 0;
tprintf("send <%s>\n", argv[1]);
if(argc > 2){
/* Send characters with inter-character delay
* (for dealing with prehistoric Micom switches that
* can't take back-to-back characters...yes, they
* still exist.)
*/
char *cp;
int32 cdelay = atol(argv[2]);
for(cp = argv[1];*cp != '\0';cp++){
bp = qdata(cp,1);
asy_send(ifp->dev,bp);
pause(cdelay);
}
} else {
bp = qdata( argv[1], (int16)strlen(argv[1]) );
if (ifp->trace & IF_TRACE_RAW)
raw_dump( ifp, IF_TRACE_OUT, bp );
asy_send( ifp->dev, bp );
}
return 0;
}
static int
dodial_speed(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
if (Skip[Depth])
return 0;
if ( argc < 2 ) {
tprintf( "current speed = %lu bps\n", Asy[ifp->dev].speed );
return 0;
}
tprintf("speed %ld\n", atol(argv[1]));
return asy_speed( ifp->dev, atol( argv[1] ) );
}
static int
dodial_status(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
int param;
if (Skip[Depth])
return 0;
if ( ifp->iostatus == NULL )
return -1;
if ( (param = devparam( argv[1] )) == -1 )
return -1;
(*ifp->iostatus)( ifp, param, atol( argv[2] ) );
return 0;
}
static int
dodial_wait(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
register int c = -1;
if (Skip[Depth])
return 0;
alarm( atol( argv[1] ) );
if ( argc == 2 ) {
tprintf("wait %ld\nimsg <", atol(argv[1]));
tflush();
while ( (c = get_asy(ifp->dev)) != -1 ) {
tputc( c &= 0x7F );
tflush();
}
alarm( 0L );
tprintf(">\n");
return 0;
} else {
register char *cp = argv[2];
tprintf("waitfor <%s>\nimsg <", argv[2]);
tflush();
while ( *cp != '\0' && (c = get_asy(ifp->dev)) != -1 ) {
tputc( c &= 0x7F );
tflush();
if (*cp++ != c) {
cp = argv[2];
}
}
if ( argc > 3 ) {
if ( stricmp( argv[3], "speed" ) == 0 ){
int32 speed = 0;
while ( (c = get_asy(ifp->dev)) != -1 ) {
tputc( c &= 0x7F );
tflush();
if ( isdigit(c) ) {
speed *= 10;
speed += c - '0';
} else {
alarm( 0L );
tprintf("> ok\n");
return asy_speed( ifp->dev, speed );
}
}
} else {
tprintf("> bad command\n");
return -1;
}
}
}
alarm( 0L );
tprintf("> %s\n", (c == -1? "failed": "ok"));
return ( c == -1 );
}
static int
dodial_failmode(argc, argv, p)
int argc;
char **argv;
void *p;
{
if (Skip[Depth])
return 0;
tprintf("failmode %s\n", argv[1]);
return setbool(&Failmode, "Continue on dial command failure", argc, argv);
}
static int
dodial_iffail(argc, argv, p)
int argc;
char **argv;
void *p;
{
if (!Skip[Depth])
{
if (SkipOverride == -1)
{
SkipOverride = Skip[Depth];
OverrideDepth = Depth;
}
Skip[Depth] = !Failed;
}
return cmdparse(dial_cmds, argv[1], p);
}
static int
dodial_ifok(argc, argv, p)
int argc;
char **argv;
void *p;
{
if (!Skip[Depth])
{
if (SkipOverride == -1)
{
SkipOverride = Skip[Depth];
OverrideDepth = Depth;
}
Skip[Depth] = Failed;
}
return cmdparse(dial_cmds, argv[1], p);
}
static int
dodial_begin(argc, argv, p)
int argc;
char **argv;
void *p;
{
if (Depth == MAXDEPTH)
{
Depth = -1;
tputs("Blocks nested too deeply\n");
return -1;
}
if (!Skip[Depth])
tputs("begin\n");
Skip[Depth + 1] = Skip[Depth];
Depth++;
return 0;
}
static int
dodial_end(argc, argv, p)
int argc;
char **argv;
void *p;
{
if (!Skip[Depth])
tputs("end\n");
if (Depth-- == 0)
{
tputs("`end' without `begin'\n");
return -1;
}
return 0;
}
static int
dodial_exit(argc, argv, p)
int argc;
char **argv;
void *p;
{
if (Skip[Depth])
return 0;
if (argc > 1)
tprintf("exit %d\n", atoi(argv[1]));
else
tputs("exit\n");
Depth = -1;
return (argc > 1? atoi(argv[1]): Failed);
}
/*
* cmdparse sends blank lines to the first command, sigh
*/
static int
dodial_nothing(argc, argv, p)
int argc;
char **argv;
void *p;
{
return 0;
}
#endif /* DIALER */